<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>打砖块</title>
  <style>
    .container {
      position: relative;
      width: 500px;
      height: 500px;
      margin: 60px auto 0;
      border: 1px solid #000;
    }

    .brickBox {
      position: absolute;
      left: 0;
      top: 0;
      width: 500px;
      height: 300px;
    }

    .ball {
      position: absolute;
      left: 235px;
      bottom: 30px;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      background-color: red;
    }

    .slider {
      position: absolute;
      left: 175px;
      bottom: 0;
      width: 150px;
      height: 30px;
      text-align: center;
      line-height: 30px;
      background-color: #0f0;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="brickBox"></div>
    <div class="ball"></div>
    <div class="slider">点击我开始游戏</div>
  </div>
</body>
<script>
  // 获取元素
  const container = document.querySelector('.container');
  const brickBox = document.querySelector('.brickBox');
  const ball = document.querySelector('.ball');
  const slider = document.querySelector('.slider');

  // 定义小球的移动速度
  let speedX = 5;
  let speedY = 5;
  // 定义砖块的宽高
  let brickWidth = 100;
  let brickHeight = 30;
  // 计算brickBox中可以容纳砖块的个数
  let brickNum = brickBox.clientWidth * brickBox.clientHeight / brickWidth / brickHeight;
  // 一行可以容纳多少个砖块，有几列
  let brickColNum = brickBox.clientWidth / brickWidth;

  // 循环创建砖块
  for (let i = 0; i < brickNum; i++) {
    let brick = document.createElement('div');
    // 设置砖块的位置和样式
    setStyle(brick, {
      position: 'absolute',
      left: (i % brickColNum) * brickWidth + 'px',
      top: parseInt(i / brickColNum) * brickHeight + 'px',
      width: brickWidth + 'px',
      height: brickHeight + 'px',
      backgroundColor: getColor()
    });
    brickBox.appendChild(brick);
  }

  let flag = true; // 节流阀

  slider.onclick = function () {
    this.innerHTML = '移动我来打砖块';
    let l = ball.offsetLeft;
    let t = ball.offsetTop;
    // 防止多次点击slider，开启多个定时器
    if (flag) {
      flag = false;
      let timer = setInterval(() => {
        // 控制小球上下移动，限制出上界
        if (bump(slider, ball) || t <= 0) {
          speedY = -speedY;
        }
        // 限制小球左右出界
        if (l >= container.clientWidth - ball.offsetWidth || l <= 0) {
          speedX = -speedX;
        }
        // 当小球与砖块碰撞时，移除被碰撞的砖块
        for (let i = 0; i < brickBox.children.length; i++) {
          if (bump(brickBox.children[i], ball)) {
            speedY = -speedY; // 改变小球移动轨迹
            brickBox.removeChild(brickBox.children[i]);
            break; // 跳出循环，提升执行效率
          }
        }
        // 当小球移动到container底部时，游戏结束
        if (t >= container.clientHeight - ball.offsetHeight) {
          clearInterval(timer);
          alert('游戏结束');
          return;
        }
        // 当小球将所有的砖块击中时，游戏通关
        if (brickBox.childElementCount <= 0) {
          clearInterval(timer);
          alert('游戏通关');
          return;
        }
        // 小球位置变化
        l += speedX;
        t += speedY;
        ball.style.left = l + 'px';
        ball.style.top = t + 'px';
      }, 20);
    }
    // 只有slider被点击过，才会执行移动事件函数
    container.onmouseover = function () {
      container.onmousemove = function (e) {
        let x = e.pageX - container.offsetLeft - slider.offsetWidth / 2;
        // 限制slider左右出界
        if (x <= 0) {
          x = 0;
        }
        if (x >= container.clientWidth - slider.offsetWidth) {
          x = container.clientWidth - slider.offsetWidth;
        }
        slider.style.left = x + 'px';
      }
    }
  }

  // 节点碰撞时进行判断
  // 1.小球和滑动条碰撞
  // 2.小球和砖块碰撞
  function bump(node1, node2) {
    if (
      node1.offsetLeft > node2.offsetLeft + node2.offsetWidth ||
      node1.offsetTop > node2.offsetTop + node2.offsetHeight ||
      node2.offsetLeft > node1.offsetLeft + node1.offsetWidth ||
      node2.offsetTop > node1.offsetTop + node1.offsetHeight
    ) {
      return false;
    }
    return true;
  }

  // 设置元素样式
  function setStyle(ele, styleObj) {
    for (let attr in styleObj) {
      ele.style[attr] = styleObj[attr];
    }
  }

  // 获取随机整数
  function getRandom(a, b = 0) {
    let max = Math.max(a, b);
    let min = Math.min(a, b);
    return Math.floor(Math.random() * (max - min) + 1) + min;
  }

  function getColor(hex = false) {
    // 16进制颜色格式
    if (hex) {
      let color = '#';
      for (let i = 0; i < 3; i++) {
        let num = getRandom(255).toString(16); // 语法：(number).toString(进制) 注意：括号不可以遗漏！
        color += `${num.length < 2 ? '0' + num : num}`; // 位数不足，用0补齐
      }
      return color;
    }
    // 默认使用RGB颜色格式
    return `rgb(${getRandom(255)},${getRandom(255)},${getRandom(255)})`;
  }
</script>

</html>